package com.linsen.erp.admin.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linsen.core.common.enums.DeleteType;
import com.linsen.core.common.exception.BaseException;
import com.linsen.core.common.tree.TreeUtils;
import com.linsen.core.common.util.ConvertUtil;
import com.linsen.erp.admin.entity.DeptEntity;
import com.linsen.erp.admin.entity.UserEntity;
import com.linsen.erp.admin.mapper.DeptMapper;
import com.linsen.erp.admin.provider.dto.DeptDTO;
import com.linsen.erp.admin.provider.enums.DeptTypeEnum;
import com.linsen.erp.admin.provider.vo.DeptVO;
import com.linsen.erp.admin.service.IDeptService;
import com.linsen.erp.admin.service.IEmployeeService;
import com.linsen.erp.admin.service.IUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 部门表 服务实现类
 * </p>
 *
 * @author zhaoyong
 * @since 2023-07-24
 */
@Service
@RequiredArgsConstructor
public class DeptServiceImpl extends ServiceImpl<DeptMapper, DeptEntity> implements IDeptService {

    private IUserService iUserService;
    @Autowired
    public void setiUserService(IUserService iUserService) {
        this.iUserService = iUserService;
    }

    private IEmployeeService iEmployeeService;
    @Autowired
    public void setiEmployeeService(IEmployeeService iEmployeeService) {
        this.iEmployeeService = iEmployeeService;
    }

    @Override
    public List<String> getSubDeptidList(String deptid) {
        Map<String, List<DeptEntity>> pidMap = this.list(
                new LambdaQueryWrapper<DeptEntity>()
                        .isNotNull(DeptEntity::getPid)
                        .eq(DeptEntity::getIsDeleted, DeleteType.NORMAL.getValue())
        ).stream().collect(Collectors.groupingBy(DeptEntity::getPid));

        List<String> subDeptidList = new ArrayList<>();

        getSubDeptidList(deptid,subDeptidList,pidMap);

        return subDeptidList;
    }

    /**
     * 循环遍历
     * @param deptid
     * @param subDeptidList
     * @param pidMap
     */
    private void getSubDeptidList(String deptid, List<String> subDeptidList, Map<String, List<DeptEntity>> pidMap) {
        subDeptidList.add(deptid);

        List<DeptEntity> subDeptList = pidMap.get(deptid);
        if (ObjectUtil.isNotEmpty(subDeptList)){
            subDeptList.forEach(subDept -> {
                getSubDeptidList(subDept.getId(),subDeptidList,pidMap);
            });
        }
    }

    /**
     * 设定部门名称path（全路径）
     * @param deptId
     * @param deptMap
     * @return
     */
    private String setPath(String deptId,Map<String, DeptEntity> deptMap){
        List<String> nameList = new ArrayList<>();

        DeptEntity currentDeptEntity = deptMap.get(deptId);
        while (ObjectUtil.isNotNull(currentDeptEntity)){
            nameList.add(currentDeptEntity.getName());
            currentDeptEntity = deptMap.get(currentDeptEntity.getPid());
        }

        return String.join("/",nameList);
    }

    @Override
    public List<DeptVO> getDeptList() {
        Map<String, DeptEntity> deptMap = this.list(
                new LambdaQueryWrapper<DeptEntity>()
                        .eq(DeptEntity::getIsDeleted, DeleteType.NORMAL.getValue())
        ).stream().collect(Collectors.toMap(DeptEntity::getId, Function.identity(), (key1, key2) -> key2));

        List<DeptVO> deptList = this.getBaseMapper().getDeptList();
        deptList.forEach(deptVO -> {
            deptVO.setPath(setPath(deptVO.getId(),deptMap));

            String leaderId = deptVO.getLeaderId();
            if (ObjectUtil.isNotNull(leaderId)){
                deptVO.setLeaderVO(iEmployeeService.get(leaderId));
            }
        });

        return TreeUtils.buildTree(deptList);
    }

    @Override
    public DeptVO get(String id) {
        Map<String, DeptEntity> deptMap = this.list(
                new LambdaQueryWrapper<DeptEntity>()
                        .eq(DeptEntity::getIsDeleted, DeleteType.NORMAL.getValue())
        ).stream().collect(Collectors.toMap(DeptEntity::getId, Function.identity(), (key1, key2) -> key2));

        DeptVO deptVO = ConvertUtil.convert(deptMap.get(id), DeptVO.class);
        deptVO.setPath(setPath(id,deptMap));

        DeptEntity parentDeptEntity = deptMap.get(deptVO.getPid());
        if (ObjectUtil.isNotNull(parentDeptEntity)){
            deptVO.setParentName(parentDeptEntity.getName());
        }

        String leaderId = deptVO.getLeaderId();
        if (ObjectUtil.isNotNull(leaderId)){
            deptVO.setLeaderVO(iEmployeeService.get(leaderId));
        }

        return deptVO;
    }

    @Transactional
    @Override
    public void saveDept(DeptDTO deptDTO) {
        String pid = deptDTO.getPid();
        String name = deptDTO.getName();

        List<DeptEntity> deptList = this.list(
                new LambdaQueryWrapper<DeptEntity>()
                        .eq(DeptEntity::getName, name)
                        .eq(DeptEntity::getPid, pid)
                        .eq(DeptEntity::getIsDeleted, DeleteType.NORMAL.getValue())
        );
        if (ObjectUtil.isNotEmpty(deptList)){
            throw new BaseException("同级部门不能重名");
        }

        //不允许添加顶级部门
        if (ObjectUtil.isNull(pid)){
            throw new BaseException("顶级部门只允许存在一个");
        }

        this.save(ConvertUtil.convert(deptDTO, DeptEntity.class));
    }

    @Transactional
    @Override
    public void updateDept(DeptDTO deptDTO) {
        String id = deptDTO.getId();
        String pid = deptDTO.getPid();
        String name = deptDTO.getName();

        if (ObjectUtil.equal(pid,id)){
            throw new BaseException("不能选择自己作为新的父级节点");
        }

        List<String> subDeptidList = this.getSubDeptidList(id);
        if (subDeptidList.contains(pid)){
            throw new BaseException("不能选择下级节点作为新的父级节点");
        }

        List<DeptEntity> deptList = this.list(
                new LambdaQueryWrapper<DeptEntity>()
                        .eq(DeptEntity::getName, name)
                        .eq(DeptEntity::getPid, pid)
                        .ne(DeptEntity::getId, id)
                        .eq(DeptEntity::getIsDeleted, DeleteType.NORMAL.getValue())
        );
        if (ObjectUtil.isNotEmpty(deptList)){
            throw new BaseException("同级部门不能重名");
        }

        //修改顶级部门时，必须继续作为顶级部门存在
        DeptEntity deptEntity = this.getById(id);
        String oldPid = deptEntity.getPid();
        if (ObjectUtil.isNull(oldPid)){
            if (ObjectUtil.isNotNull(pid)){
                throw new BaseException("顶级部门不可变更层级");
            }
        }else{
            if (ObjectUtil.isNull(pid)){
                throw new BaseException("顶级部门只允许存在一个");
            }
        }

        this.updateById(ConvertUtil.convert(deptDTO, DeptEntity.class));
    }

    @Transactional
    @Override
    public void delete(String id) {
        Long subDeptCount = this.count(
                new LambdaQueryWrapper<DeptEntity>()
                        .eq(DeptEntity::getPid, id)
                        .eq(DeptEntity::getIsDeleted, DeleteType.NORMAL.getValue())
        );
        if (subDeptCount > 0){
            throw new BaseException("存在子级节点，不允许直接删除");
        }

        long userCount = iUserService.count(
                new LambdaQueryWrapper<UserEntity>()
                        .eq(UserEntity::getDeptId,id)
                        .eq(UserEntity::getIsDeleted, DeleteType.NORMAL.getValue())
        );
        if (userCount > 0){
            throw new BaseException("存在关联用户，不允许直接删除");
        }

        //不允许删除顶级部门
        DeptEntity deptEntity = this.getById(id);
        String pid = deptEntity.getPid();
        if (ObjectUtil.isNull(pid)){
            throw new BaseException("顶级部门禁止删除");
        }

        this.update(
                new UpdateWrapper<DeptEntity>().lambda()
                        .set(DeptEntity::getIsDeleted,DeleteType.DELETED.getValue())
                        .eq(DeptEntity::getId,id)
        );
    }

    @Override
    public String getParentAreaByDeptId(String deptid) {
        Map<String, DeptEntity> deptMap = this.list(
                new LambdaQueryWrapper<DeptEntity>()
                        .eq(DeptEntity::getIsDeleted, DeleteType.NORMAL.getValue())
        ).stream().collect(Collectors.toMap(DeptEntity::getId, Function.identity(), (key1, key2) -> key2));

        DeptEntity currentDeptEntity = deptMap.get(deptid);
        if (ObjectUtil.isNull(currentDeptEntity)){
            return null;
        }
        Integer type = currentDeptEntity.getType();
        if (ObjectUtil.equals(type, DeptTypeEnum.HEAD.getValue())){
            return null;
        }else if (ObjectUtil.equals(type, DeptTypeEnum.AREA.getValue())){
            return deptid;
        }else if (ObjectUtil.equals(type, DeptTypeEnum.COMPANY.getValue())){
            return currentDeptEntity.getPid();
        }else if (ObjectUtil.equals(type, DeptTypeEnum.DEPT.getValue())){
            while (!ObjectUtil.equals(currentDeptEntity.getType(),DeptTypeEnum.AREA.getValue())){
                currentDeptEntity = deptMap.get(currentDeptEntity.getPid());
            }
            return currentDeptEntity.getId();
        }
        return null;
    }

    @Override
    public String getParentCompanyByDeptId(String deptid) {
        Map<String, DeptEntity> deptMap = this.list(
                new LambdaQueryWrapper<DeptEntity>()
                        .eq(DeptEntity::getIsDeleted, DeleteType.NORMAL.getValue())
        ).stream().collect(Collectors.toMap(DeptEntity::getId, Function.identity(), (key1, key2) -> key2));

        DeptEntity currentDeptEntity = deptMap.get(deptid);
        if (ObjectUtil.isNull(currentDeptEntity)){
            return null;
        }
        Integer type = currentDeptEntity.getType();
        if (ObjectUtil.equals(type, DeptTypeEnum.HEAD.getValue())){
            return null;
        }else if (ObjectUtil.equals(type, DeptTypeEnum.AREA.getValue())){
            return null;
        }else if (ObjectUtil.equals(type, DeptTypeEnum.COMPANY.getValue())){
            return deptid;
        }else if (ObjectUtil.equals(type, DeptTypeEnum.DEPT.getValue())){
            while (!ObjectUtil.equals(currentDeptEntity.getType(),DeptTypeEnum.COMPANY.getValue())){
                currentDeptEntity = deptMap.get(currentDeptEntity.getPid());
            }
            return currentDeptEntity.getId();
        }
        return null;
    }
}
